import asyncio
import json
import logging
import os
import sys
import threading
import tkinter
import tkinter as tk
from tkinter import *
from tkinter import ttk, messagebox

from utils import project_setting

# logger_level=logging.WARN
logger_level=logging.DEBUG
logging.basicConfig(stream=sys.stdout, level=logger_level,
                    format='%(asctime)s %(name)s [%(pathname)s.%(funcname) line:%(lineno)d] %(levelname)s %(message)s')
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))

from limma_index_milvus_demo.li_demo_remote import LimmaIndexMilvusDemoRemote

# 创建主窗口
root = tk.Tk()
root.title("Milvus Demo UI")
root.geometry("1300x900")

def msg_sout(msg):
    text_box.insert(tk.END, msg)
    text_box.see(tk.END)
    print('msg_sout')

# milvus_url="http://localhost:19530"
# milvus_token='root:Milvus'
milvus_url=os.environ['ZILLIZ-MILVUS-URL']
milvus_token=os.environ['ZILLIZ-MILVUS-TOKEN']
milvus_demo_remote = LimmaIndexMilvusDemoRemote(stdout=msg_sout,
                                                milvus_url=milvus_url,
                                                milvus_token=milvus_token,
                                                embedding_model_function="OpenAIEmbedding",
                                                # embedding_model_function='OnnxEmbedding',
                                                # embedding_model_function = 'BGEM3Embedding',
                                                collection_name='limd'
                                                )
per_page_options = milvus_demo_remote.get_embedding_model_names()
# 需要放在 tk.tk() 代码后面才行
per_page_var = tkinter.StringVar(value=milvus_demo_remote.get_embedding_model_function())

# 创建按钮框架
button_frame = ttk.Frame(root)
button_frame.pack(pady=10)

# 定义按钮列表以便于禁用和启用
buttons = []

def disable_buttons():
    for button in buttons:
        button.config(state=tk.DISABLED)

def enable_buttons():
    for button in buttons:
        button.config(state=tk.NORMAL)

def button_load_data_to_documents1():
    input_dir = f'{project_setting.knowledge_files_path}/knowledge_files'
    input_files = [input_dir + '/knowledge.txt', input_dir + '/paul_graham_essay.txt', ]
    milvus_demo_remote.load_data_to_documents1(input_dir=input_dir, input_files=input_files)
def button_drop_connection():
    """"""
    milvus_collection_name_by_li = milvus_demo_remote.milvus_collection_name_by_li()
    milvus_demo_remote.drop_connection(milvus_collection_name_by_li)
    # text_box.insert(tk.END, "删除集合成功\n")

def button_create_connection():
    """"""
    if milvus_demo_remote.has_connection():
        text_box.insert(tk.END, "集合已存在,先删除集合再创建成功\n")
        return
    milvus_demo_remote.create_connection()
    text_box.insert(tk.END, "创建集合成功\n")

def button_insert_data():
    """"""
    milvus_demo_remote.insert_data()
    text_box.insert(tk.END, "插入数据成功\n因为示例的id是固定的,多次插入数据条数是增加了,但是查询不会全部显示\n")


def button_create_knowledge():
    """"""
    milvus_demo_remote.create_knowledge()
    printlnToTextBox("加载知识库成功")

def button_query():
    """"""
    printlnToTextBox(f'{"-" * 30} 开始查询 {"-" * 30} ')
    query="When was artificial intelligence founded"
    res=milvus_demo_remote.query_milvus(query)
    # text_box.insert(tk.END, f"{json.dumps(res[0])}\n")
    printlnToTextBox(f'{"-" * 30} 问题 {"-" * 30} ')
    printlnToTextBox(query)
    printlnToTextBox(f'{"-" * 30} 答案 {"-" * 30} ')
    for node in res[0]:
        # text_box.insert(tk.END, f"{json.dumps(node)}\n")
        # text_box.insert(tk.END, f"{type(node)}\n")

        content_ = node['entity']['_node_content']
        # text_box.insert(tk.END, f"{json.dumps(content_)}\n")
        obj_tmp=json.loads(content_)
        # text_box.insert(tk.END, f"{json.dumps(obj_tmp['text'])}\n")
        text_box.insert(tk.END, f"{(obj_tmp['text'])}\n")
        # text_box.insert(tk.END, f"{str(node.entity)}\n")

    # text_box.insert(tk.END, f"{json.dumps(res)}\n")

def button_limma_index_query():
    """"""
    printlnToTextBox(f'{"-" * 30} 开始查询 {"-" * 30} ')
    query="When was artificial intelligence founded"
    query="广州大学"
    res=milvus_demo_remote.limma_index_query(query)
    printlnToTextBox(f'{"-" * 30} 问题 {"-" * 30} ')
    printlnToTextBox(query)
    printlnToTextBox(f'{"-" * 30} 答案 {"-" * 30} ')
    printlnToTextBox(f"{str(res)}\n")

def button_clear_data():
    """清除数据按钮的回调函数"""
    from tkinter import messagebox
    # messagebox.showinfo("提示", "请输入查询内容")
    if messagebox.askyesno("确认清除数据", "您确定要清除所有数据吗？"):
        milvus_demo_remote.clear_data()
        text_box.insert(tk.END, "清除数据成功\n")

def button_select_embedding_model():
    """"""
    embedding_model_name = per_page_combobox.get()
    milvus_demo_remote.select_embedding_model(embedding_model_name)
    text_box.insert(tk.END, f"切换模型成功\n")

def button_drop_knowledge_by_OnnxEmbedding():
    """"""
    milvus_collection_name_by_OnnxEmbedding = milvus_demo_remote.milvus_collection_name_by_OnnxEmbedding()
    milvus_demo_remote.drop_connection(milvus_collection_name_by_OnnxEmbedding)
    # text_box.insert(tk.END, f"删除集合{milvus_collection_name_by_OnnxEmbedding}成功\n")

def button_drop_knowledge_by_sparse_OnnxEmbedding():
    """"""
    milvus_collection_name_by_sparse_OnnxEmbedding = milvus_demo_remote.milvus_collection_name_by_sparse_OnnxEmbedding()
    milvus_demo_remote.drop_connection(milvus_collection_name_by_sparse_OnnxEmbedding)
    # text_box.insert(tk.END, f"删除集合{milvus_collection_name_by_sparse_OnnxEmbedding}成功\n")

def button_set_to_OnnxEmbedding():
    per_page_combobox.set('OnnxEmbedding')
    milvus_demo_remote.set_to_OnnxEmbedding()
    text_box.insert(tk.END, f"OnnxEmbedding 切换模型成功\n")

def button_create_knowledge_by_OnnxEmbedding():
    milvus_demo_remote.create_knowledge_by_OnnxEmbedding()
    text_box.insert(tk.END, "OnnxEmbedding 加载知识库成功\n")
def button_query_by_OnnxEmbedding():
    """"""
    printlnToTextBox(f'{"-" * 30} 开始查询 {"-" * 30} ')
    query="When was artificial intelligence founded"
    res=milvus_demo_remote.query_milvus_by_OnnxEmbedding(query)
    printlnToTextBox(f'{"-" * 30} 问题 {"-" * 30} ')
    printlnToTextBox(query)
    printlnToTextBox(f'{"-" * 30} 答案 {"-" * 30} ')
    printlnToTextBox(f"{str(res)}")

def button_set_to_sparse_OnnxEmbedding():
    per_page_combobox.set('OnnxEmbedding')
    milvus_demo_remote.set_to_sparse_OnnxEmbedding()
    text_box.insert(tk.END, f"OnnxEmbedding 切换模型成功\n")

def button_create_knowledge_by_sparse_OnnxEmbedding():
    milvus_demo_remote.create_knowledge_by_sparse_OnnxEmbedding()
    text_box.insert(tk.END, "OnnxEmbedding 加载知识库成功\n")
def button_query_by_sparse_OnnxEmbedding():
    """"""
    printlnToTextBox(f'{"-" * 30} 开始查询 {"-" * 30} ')
    query="When was artificial intelligence founded"
    res=milvus_demo_remote.query_milvus_by_sparse_OnnxEmbedding(query)
    printlnToTextBox(f'{"-" * 30} 问题 {"-" * 30} ')
    printlnToTextBox(query)
    printlnToTextBox(f'{"-" * 30} 答案 {"-" * 30} ')
    printlnToTextBox(f"OnnxEmbedding {str(res)}")

def button_query_by_sparse_OnnxEmbedding2():
    """"""
    printlnToTextBox(f'{"-" * 30} 开始查询 {"-" * 30} ')
    query="When was artificial intelligence founded"
    res=milvus_demo_remote.query_milvus_by_sparse_OnnxEmbedding2(query)
    printlnToTextBox(f'{"-" * 30} 问题 {"-" * 30} ')
    printlnToTextBox(query)
    printlnToTextBox(f'{"-" * 30} 答案 {"-" * 30} ')
    printlnToTextBox(f"OnnxEmbedding {str(res)}")

def printlnToTextBox(msg):
    text_box.insert(tk.END, f"{msg}\n")
    text_box.see(tk.END)

#处理线程,避免UI卡死
action_thread = None
def button_async_fun(_fun):
    disable_buttons()
    root.update()  # 更新主界面以显示进度
    def async_fun(_fun):
        try:
            _fun()
            """"""
        except Exception as e:
            text_box.insert(tk.END, f"执行失败: {str(e)}\n")
            # 打印完整的异常信息
            import traceback
            traceback.print_exc(file=sys.stderr)
        enable_buttons()


    global action_thread
    if action_thread is None or not action_thread.is_alive():
        action_thread = threading.Thread(target=async_fun,args=(_fun,))
        action_thread.start()
        # 等待线程结束,调用这个函数会阻塞线程,直到线程结束
        # action_thread.join()
        # enable_buttons()
    else:
        enable_buttons()
        messagebox.showwarning("提示", "请等待上一个操作完成")

def button_async_fun2(_fun):
    disable_buttons()
    root.update()  # 更新主界面以显示进度
    async def async_fun2(_fun):
        try:
            _fun()
            """"""
        except Exception as e:
            text_box.insert(tk.END, f"执行失败: {str(e)}\n")
            # 打印完整的异常信息
            import traceback
            traceback.print_exc(file=sys.stderr)
        enable_buttons()

    asyncio.run(async_fun2(_fun))

# 添加创建集合按钮
create_collection_button = ttk.Button(button_frame, text="创建集合", command=lambda: button_async_fun(button_create_connection))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

# 添加清除数据按钮
create_collection_button = ttk.Button(button_frame, text="清除数据", command=lambda: button_async_fun(button_clear_data))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="插入数据", command=lambda: button_async_fun(button_insert_data))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

# 通用按钮框架
button_frame = ttk.Frame(root)
button_frame.pack(pady=10)

label = ttk.Label(button_frame, text="通用按钮:")
label.pack(side=LEFT)


create_collection_button = ttk.Button(button_frame, text="读取文档1", command=lambda: button_async_fun(button_load_data_to_documents1))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)


# 创建按钮框架
button_frame = ttk.Frame(root)
button_frame.pack(pady=10)

per_page_combobox = ttk.Combobox(button_frame,style='', width=30,height=4, textvariable=per_page_var, values=per_page_options)
per_page_combobox.pack(side=LEFT)
per_page_combobox.bind("<<ComboboxSelected>>", lambda event: button_async_fun(button_select_embedding_model))
# per_page_combobox.set(per_page_var)
buttons.append(per_page_combobox)

create_collection_button = ttk.Button(button_frame, text="删除集合", command=lambda: button_async_fun(button_drop_connection))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="加载知识库", command=lambda: button_async_fun2(button_create_knowledge))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="查询", command=lambda: button_async_fun(button_limma_index_query))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

button_frame = ttk.Frame(root)
button_frame.pack(pady=10)

label = ttk.Label(button_frame, text="OnnxEmbedding 模型(768 dim)[OK] 密集向量:")
label.pack(side=LEFT)


create_collection_button = ttk.Button(button_frame, text="删除集合", command=lambda: button_async_fun(button_drop_knowledge_by_OnnxEmbedding))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="设置模型", command=lambda: button_async_fun(button_set_to_OnnxEmbedding))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="加载知识库", command=lambda: button_async_fun2(button_create_knowledge_by_OnnxEmbedding))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="查询", command=lambda: button_async_fun(button_query_by_OnnxEmbedding))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

button_frame = ttk.Frame(root)
button_frame.pack(pady=10)

label = ttk.Label(button_frame, text="OnnxEmbedding 模型(768 dim)[OK] 密集向量稀疏向量混合检索:")
label.pack(side=LEFT)

create_collection_button = ttk.Button(button_frame, text="删除集合", command=lambda: button_async_fun(button_drop_knowledge_by_sparse_OnnxEmbedding))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="设置模型", command=lambda: button_async_fun(button_set_to_sparse_OnnxEmbedding))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="加载知识库", command=lambda: button_async_fun2(button_create_knowledge_by_sparse_OnnxEmbedding))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="查询", command=lambda: button_async_fun(button_query_by_sparse_OnnxEmbedding))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="查询2(PromptTemplate)", command=lambda: button_async_fun(button_query_by_sparse_OnnxEmbedding2))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)

create_collection_button = ttk.Button(button_frame, text="查询(使用milvus直接查询llama_index数据)", command=lambda: button_async_fun(button_query))
create_collection_button.pack(side=LEFT)
buttons.append(create_collection_button)


# 创建框架
button_frame = ttk.Frame(root)
button_frame.pack(fill=X)
# 添加信息标签
info_label = ttk.Label(button_frame, text="调试信息", font=("TkDefaultFont", 10))
info_label.pack(side=LEFT)

create_collection_button = ttk.Button(button_frame, text="清除调试信息", command=lambda: text_box.delete(1.0, tk.END))
create_collection_button.pack(side=RIGHT)
buttons.append(create_collection_button)


# 创建外框架以容纳纵向滚动条和另一个外框架
frame = ttk.Frame(root)
frame.pack(fill=BOTH, expand=True)

# 创建外框架以容纳横向滚动条和文本框
panel=ttk.Frame(frame)
panel.pack(side=LEFT,fill=BOTH, expand=True)

# 创建多行文本框
#wrap=tk.WORD
# text_box = tk.Text(panel, wrap=tk.NONE, height=55, width=170)
# text_box.pack(pady=10)

text_box = tk.Text(panel, wrap=tk.NONE)
text_box.pack(side=TOP, fill=BOTH, expand=True)

# 创建滚动条并将其与文本框关联
scrollbar_y = tk.Scrollbar(frame, command=text_box.yview)

# 将横向滚动条放置在 panel 中, 这样横向滚动条就可以正常显示
scrollbar_x = ttk.Scrollbar(panel, orient=HORIZONTAL, command=text_box.xview)  # 新增：创建横向滚动条

scrollbar_y.pack(side=RIGHT, fill=Y)
scrollbar_x.pack(side=BOTTOM, fill=X)  # 新增：放置横向滚动条

text_box.config(yscrollcommand=scrollbar_y.set,xscrollcommand=scrollbar_x.set)

# print('milvus_demo_remote.init()')
# milvus_demo_remote.init()

def root_after_init():
    disable_buttons()
    milvus_demo_remote.init()
    # per_page_combobox.set('OnnxEmbedding')
    per_page_combobox.set(milvus_demo_remote.get_embedding_model_function())
    enable_buttons()

# 使用after方法确保在窗口完全可见后执行函数
root.after(100,root_after_init)
# 运行主循环
root.mainloop()